# encoding :utf-8
from AgtUtil import *
from random import shuffle


class Traverse(object):
    def __init__(self, temp_path, output_path):
        self.agt = Agt(temp_path, output_path, click_delay=2)
        self.max_deep = 0
        self.max_restart = 0
        self.curr_deep = 0

    def start_single(self, apk_path, max_deep=6, max_restart=20, click_delay=2):
        self.agt.click_delay = click_delay
        self.max_deep = max_deep
        self.max_restart = max_restart
        self.curr_deep = 0
        self.start_apk(apk_path)
        self.first_state()
        trans_info = self.agt.curr_apk.utg.output_utg()
        state_info = self.agt.curr_apk.output_state_info()
        self.agt.output_result(state_info, trans_info)

    def start_apk(self, apk_path):
        self.agt.set_curr_apk(apk_path)
        if not self.agt.curr_apk.is_valid_apk:
            return False
        # init, until this apk is started
        self.agt.install_apk()
        self.agt.start_app(5)
        logging.info('APP TESTING: ' + apk_path)
        logging.info('APP package_name: ' + self.agt.curr_apk.package_name)
        for i in range(5):
            if self.agt.check_current_app():
                break
            else:
                self.agt.start_app(5)
        if not self.agt.check_current_app():
            logging.critical('Starting app fail !')
            return False

    def first_state(self):
        # screenshot -> create state -> match image -> clickable position
        first_state_screenshot = self.agt.take_screenshot(output=True)
        first_state = self.agt.create_state_via_screenshot(first_state_screenshot)
        first_state.fill_position_dict(self.agt.match_image(first_state))
        self.agt.curr_apk.state_stack.append(first_state)
        self.agt.curr_apk.state_list.append(first_state)
        restart_time = 0
        # traverse all clickable in the first stage
        for img, clicked in first_state.position_dict.items():
            if restart_time > self.max_restart:
                return
            if clicked == 0:
                click_result = self.agt.click_general((img[1], img[2]))
                first_state.position_dict[img] = 1
                if click_result:
                    self.callback_new_state_reached()
                    self.agt.restart_app(delay=8)
                    restart_time += 1
                    self.curr_deep = 1
                    self.agt.curr_apk.state_stack = []
                    self.agt.curr_apk.state_stack.append(first_state)
                else:
                    continue
        self.agt.stop_app()

    def callback_new_state_reached(self):
        # current apk check
        if not self.agt.check_current_app():
            self.agt.start_app(5)
            self.curr_deep = 1
            first_state = self.agt.curr_apk.state_stack[0]
            self.agt.curr_apk.state_stack = []
            self.agt.curr_apk.state_stack.append(first_state)
            return
        # deep check
        self.curr_deep += 1
        logging.info('CURRENT DEEP : %d', self.curr_deep)
        if self.curr_deep > self.max_deep:
            back_result = self.agt.click_back()
            if back_result == 0:
                return
            elif back_result == 1:
                self.curr_deep -= 2
                self.callback_new_state_reached()
            else:
                self.callback_new_state_reached()
        # new state traverse , shuffle
        curr_state = self.agt.curr_apk.state_stack[-1]
        img_list = curr_state.position_dict.keys()
        shuffle(img_list)
        for img in img_list:
            clicked = curr_state.position_dict[img]
            if clicked == 0:
                click_result = self.agt.click_general((img[1], img[2]))
                curr_state.position_dict[img] = 1
                if click_result:
                    self.callback_new_state_reached()
                    break
        # no shuffle
        # for img, clicked in curr_state.position_dict.items():
        #     if clicked == 0:
        #         click_result = self.agt.click_general((img[1], img[2]))
        #         curr_state.position_dict[img] = 1
        #         if click_result:
        #             self.callback_new_state_reached()
        #             break
        # end , click back
        back_result = self.agt.click_back()
        if back_result == 0:
            return
        elif back_result == 1:
            self.curr_deep -= 2
            self.callback_new_state_reached()
        else:
            self.callback_new_state_reached()
